﻿#include <QDebug>
#include <CoreAudio/CoreAudio.h>
#include <AudioToolbox/AudioToolbox.h>

#import <AVFoundation/AVFoundation.h>

#include "MacMediaDevice.h"

#define KVirtualAudioUID "AudioDevice_UID"

MacMediaDevice::MacMediaDevice(QObject *parent):MediaDevice(parent) {}

MacMediaDevice::~MacMediaDevice() {}


void defaultDeivce()
{
    AudioDeviceID inID = kAudioDeviceUnknown;
    AudioDeviceID outID = kAudioDeviceUnknown;

    UInt32 propertySize0 = sizeof(inID);
    UInt32 propertySize1 = sizeof(outID);

    AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propertySize0, &inID);
    AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice , &propertySize1, &outID);

    qDebug() << inID;
    qDebug() << outID;
}

int MacMediaDevice::getIDFromUID(const QString &uid)
{
    CFStringRef virtualDeviceAudioUID = uid.toCFString();
    CFStringRef *inDeviceAudioUID = &virtualDeviceAudioUID;

    AudioDeviceID virtualAudioDeviceID = kAudioDeviceUnknown;

    AudioObjectPropertyAddress proprtyAddress = {};
    proprtyAddress.mSelector = kAudioHardwarePropertyTranslateUIDToDevice;
    proprtyAddress.mScope = kAudioObjectPropertyScopeGlobal;
    proprtyAddress.mElement = kAudioObjectPropertyElementMaster;


    UInt32 inSize = sizeof(inDeviceAudioUID);
    uint32 outSize = sizeof(virtualAudioDeviceID);


    OSStatus ret = AudioObjectGetPropertyData(kAudioObjectSystemObject,
                                              &proprtyAddress,
                                              inSize,
                                              inDeviceAudioUID,
                                              &outSize,
                                              &virtualAudioDeviceID);

    if (virtualAudioDeviceID == kAudioDeviceUnknown) {
        qDebug() << "not found";
        return -1;
    }

    return virtualAudioDeviceID;
}

QList<QPair<QString,QString>> MacMediaDevice::getDeviceList(MediaDeviceType type)
{
    QList<QPair<QString,QString>> deviceList;

    AudioObjectPropertyAddress addr = {
        .mScope = kAudioObjectPropertyScopeGlobal,
        .mElement = kAudioObjectPropertyElementMaster,
        .mSelector = kAudioHardwarePropertyDevices,
    };

    UInt32      size     = 0;

    OSStatus status;

    status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &addr, 0, nullptr, &size);

    if (status != noErr) {
        qDebug() << "get kAudioHardwarePropertyDevices data size error";
        return deviceList;
    }

    int count = size / sizeof(AudioDeviceID);

    AudioDeviceID *ids = (AudioDeviceID *)malloc(size);

    status = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, 0, nullptr, &size, ids);

    if(status != noErr) {
        free(ids);
        return deviceList;
    }

    for(int i = 0; i < count ; i++) {
        UInt32 in_size = 0;
        AudioObjectPropertyAddress input_addr = {
            .mSelector = kAudioDevicePropertyStreams,
            .mElement  = kAudioObjectPropertyElementMaster,
        };

        if (type == MediaDeviceType_Input) {
            input_addr.mScope = kAudioDevicePropertyScopeInput;
        } else {
            input_addr.mScope = kAudioDevicePropertyScopeOutput;
        }

        /* 跳过不是音频输入的设备 */
        AudioObjectGetPropertyDataSize(ids[i], &input_addr, 0, nullptr, &in_size);
        if (!in_size)
            continue;

        QPair<QString,QString> device;

        UInt32 cf_size = sizeof(CFStringRef);
        CFStringRef deviceName = nullptr;
        input_addr.mSelector = kAudioDevicePropertyDeviceNameCFString;
        status = AudioObjectGetPropertyData(ids[i], &input_addr, 0, nullptr, &cf_size, &deviceName);

        if (status != noErr)
            continue;

        device.first = QString::fromCFString(deviceName);
        CFRelease(deviceName);

        CFStringRef uid = nullptr;

        input_addr.mSelector = kAudioDevicePropertyDeviceUID;

        status =  AudioObjectGetPropertyData(ids[i], &input_addr, 0, nullptr, &cf_size, &uid);

        if (status != noErr)
            continue;

        //        device.second = QString::fromCFString(uid);
        device.second = QString::number(ids[i]);
        CFRelease(uid);

        deviceList.push_back(device);
    }

    free(ids);

    return deviceList;
}

